import { Bezier } from "../Common/Components/Bezier";
import { Props } from "../Common/Components/Props";
import { gameHelper } from "./GameHelpler";

export class TweenUtils {
    /**
        *  二阶贝塞尔曲线 运动
        * @param target
        * @param {number} duration
        * @param {} c1 起点坐标
        * @param {} c2 控制点
        * @param {cc.Vec2} to 终点坐标
        * @param opts
        * @returns {any}
        */
    static bezierTo(target: any, duration: number, c1: cc.Vec2, c2: cc.Vec2, to: cc.Vec2, opts: any) {
        opts = opts || Object.create(null);
        /**
         * @desc 二阶贝塞尔
         * @param {number} t 当前百分比
         * @param {} p1 起点坐标
         * @param {} cp 控制点
         * @param {} p2 终点坐标
         * @returns {any}
         */
        let twoBezier = (t: number, p1: cc.Vec2, cp: cc.Vec2, p2: cc.Vec2) => {
            let x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;
            let y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;
            return cc.v2(x, y);
        };
        opts.onUpdate = (arg: cc.Vec2, ratio: number) => {
            target.position = twoBezier(ratio, c1, c2, to);
        };
        return cc.tween(target).to(duration, {}, opts);
    }
    /**
     * 按局部坐标来计算
     * @param node 节点
     * @param startPos 起点
     * @param endPos 终点
     * @param height 高度（控制点高度 = 终点高度+高度）
     * @param duration 时长
     * @param easing 缓动
     * @returns 
     */
    static jumpTo(node: cc.Node = null, startPos: cc.Vec2, endPos: cc.Vec2, height: number, duration: number, easing?: string | ((k: number) => number), updateCalback?: Function): cc.Tween {
        return TweenUtils.tween(node)
            .to(duration, { position: endPos, }, {
                progress: (start, end, current, ratio) => {
                    // let node = <cc.Node>target;
                    let pos = Bezier.jumpTo(startPos, endPos, height, ratio);
                    // gameHelper.drawAny(null, node.parent.getComponent(UITransform).convertToWorldSpaceAR(pos));
                    // gameHelper.drawAny(null, a);
                    // node.setPosition(pos)
                    gameHelper.addCompOnce(node, Props).position = pos
                    if (updateCalback) updateCalback(node, ratio);
                },
                easing: easing || 'quadInOut',
            })
    }
    /**
     * 按世界坐标来计算
     * @param node 节点
     * @param startPos 起点
     * @param endPos 终点
     * @param height 高度（控制点高度 = 终点高度+高度）
     * @param duration 时长
     * @param easing 缓动
     * @returns 
     */
    static jumpToWorld(node: cc.Node = null, startPos: cc.Vec2, endPos: cc.Vec2, height: number, duration: number, easing?: string | ((k: number) => number), updateCalback?: Function): cc.Tween {
        return TweenUtils.tween(node)
            .to(duration, { worldPosition: endPos }, {
                progress: (start, end, current, ratio) => {
                    // let node = <cc.Node>target;
                    let pos = Bezier.jumpTo(startPos, endPos, height, ratio);
                    // console.log('aaaaaa', pos)
                    // gameHelper.drawAny({ radius: 50 }, (pos));
                    // gameHelper.drawAny(null, a);
                    gameHelper.addCompOnce(node, Props).worldPosition = pos
                    // node.setWorldPosition(pos)
                    if (updateCalback) updateCalback(node, ratio);
                },
                easing: easing || 'quadInOut',
            })

    }
    /**
     * 按局部坐标来计算
     * @param node 节点
     * @param startPos 起点
     * @param endPos 偏移向量
     * @param height 高度（控制点高度 = 终点高度+高度）
     * @param duration 时长
     * @param easing 缓动
     * @returns 
     */
    static jumpBy(node: cc.Node = null, startPos: cc.Vec2, endPos: cc.Vec2, height: number, duration: number, easing?: string | ((k: number) => number)): cc.Tween {
        endPos.add(startPos)
        return TweenUtils.tween(node)
            .to(duration, { position: endPos, }, {
                progress: (start, end, current, ratio) => {
                    // let node = <cc.Node>target;
                    let pos = Bezier.jumpTo(startPos, endPos, height, ratio);

                    // gameHelper.drawAny(null, node.parent.getComponent(UITransform).convertToWorldSpaceAR(pos));
                    // gameHelper.drawAny(null, a);
                    node.setPosition(pos)
                },
                easing: easing || 'quadInOut',
            })
    }
    static tweenPromise(tw: cc.Tween): Promise<cc.Tween> {
        return new Promise<cc.Tween>((resolve, reject) => {
            tw.call(() => { resolve(null); }
            ).start();
        })
    }
    static tweenPromiseAll(tweens: cc.Tween[]) {
        return new Promise(success => {
            let promiseArr: Promise<cc.Tween>[] = [];
            tweens.forEach(v => {
                promiseArr.push(this.tweenPromise(v))
            })
            Promise.all(promiseArr).then((arr) => {
                success(true);
            })
        })
    }
    static tweenPromiseRace(tweens: cc.Tween[]) {
        return new Promise(success => {
            let promiseArr: Promise<cc.Tween>[] = [];
            tweens.forEach(v => {
                promiseArr.push(this.tweenPromise(v))
            })
            Promise.race(promiseArr).then(() => {
                success(true);
            })
        })
    }

    static tween(target: cc.Node): cc.Tween {
        return cc.tween(target);
    }
    static stopAllByTarget(target: cc.Node) {
        return cc.Tween.stopAllByTarget(target)
    }
    static stopByTag(tag: (number), target: cc.Node) {
        return cc.Tween.stopByTag(tag, target)
    }
}